<template>
    <div>
        <div class="bh bend">
            <zb-btn-group
                :btns="btnList"
                :data="btnsData"
                :isCheckPermissions="isCheckPermissions"
            ></zb-btn-group>
        </div>
        <!-- 使用v-show是为了避免需要设值数据时找不到对象 -->
        <formCreate
            class="mt_10"
            ref="form"
            v-show="isSearch"
            v-bind="$attrs"
            v-on="$listeners"
            :option="options"
            :rule="searchRules"
        ></formCreate>
    </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit, Watch } from "vue-property-decorator";
import formCreate from "@form-create/element-ui";
import {
    defaults,
    concat,
    forEach,
    isEmpty,
    cloneDeep,
    set,
    unset,
    compact
} from "lodash";
import { mixinCondition } from "@/components/mixin/Condition";
/**
 *
 * 列表查询头组件，可以根据传入关联数据动态控制具体按钮显示隐藏
 * 表单创建基于 http://www.form-create.com/v2/guide/
 * 可用组件基于 http://www.form-create.com/v2/element-ui/
 */
@Component({
    name: "ZbHeaderSearch",
    mixins: [mixinCondition],
    components: {
        // eslint-disable-next-line no-undef
        formCreate: formCreate.$form()
    }
})
export default class ZbHeaderSearch extends Vue {
    // 点击查询按钮后抛出事件
    @Emit("search") search() {}
    // 点击清空按钮后是否执行查询
    @Prop({ default: true }) readonly isClearSearch!: Boolean;
    // 是否必须检查权限
    @Prop({ default: true }) readonly isCheckPermissions!: Boolean;
    // 表单配置
    // 可用配置参考 http://www.form-create.com/v2/element-ui/
    @Prop() readonly rule!: Array<any>;
    // 表单默认配置
    // 可覆盖
    defaulrules: Object = {
        props: {
            clearable: true
        }
    };
    // 表单最终配置
    get searchRules() {
        const defaulrules = this.defaulrules;
        // 循环辩论加入默认配置
        return forEach(this.rule, (item) => {
            defaults(item, defaulrules);
        });
    }

    // 按钮组关联数据
    // 用于处理权限
    @Prop()
    readonly btnsData!: Object;

    // 提交数据处理配置
    // 可以用于cascader和DatePicker，将其数组数据转为对应的字段数据
    // field对应field配置
    // fields 按照组件输出顺序[value1,value2]对应的提交字段名称
    // isLast 是否只提交fields中最后一个有效值，默认否
    // 例如 表单数据{section_day:[value1,value2],add:["add1", "add2", "add3"]}会转换为
    // {startDate:value1,endDate:value2,province:'add1',mayor:'add2',county:'add3'}
    // valueTransform: [
    //     {
    //         field: "section_day",
    //         fields: ["startDate", "endDate"]
    //     },
    //     {
    //         field: "add",
    //         fields: ["province", "mayor", "county"]
    //     }
    // ],
    //
    @Prop({
        default: function () {
            return [];
        }
    })
    readonly valueTransform!: any;

    // 查询按钮配置
    @Prop()
    readonly searchBtn!: Object;
    // 查询按钮默认配置
    // 可覆盖，请勿覆盖handleClick配置
    defaultSearchBtn: Object = {
        label: "查询",
        class: "btn-blue",
        handleClick: this.onSearchClick
    };
    // 查询按钮最终配置
    get searchBtnConfig() {
        return defaults(this.searchBtn, this.defaultSearchBtn);
    }

    // 是否显示查询模块
    get isSearch() {
        const me: any = this,
            btnsData = me.btnsData;
        // 如果没有按钮数据，默认显示
        if (isEmpty(btnsData) && !me.isCheckPermissions) {
            return true;
        }
        // 根据按钮数据和校验配置确定是否显示
        return me.checkCondition(me.searchBtnConfig, btnsData);
    }
    // 监听isSearch变化
    @Watch("isSearch")
    updateIsSearch(v: any) {
        if (v) {
            // 显示查询模块时重新渲染，避免布局错误
            const me: any = this;
            me.$nextTick(() => {
                me.getForm().refresh(true);
            });
        }
    }

    // 清空按钮配置
    @Prop() readonly clearBtn!: Object;
    // 清空按钮默认配置
    // 可覆盖，请勿覆盖handleClick配置
    defaultClearBtn: Object = {
        label: "清空",
        class: "btn-clear",
        handleClick: this.onClearClick
    };
    // 清空按钮最终配置
    get clearBtnConfig() {
        return defaults(this.clearBtn, this.defaultClearBtn);
    }

    // 按钮组
    // isDrop: true, 是否在更多按钮组
    // sort:1, 排序值，默认为1
    // label: "详情", 文本
    // class: "btn-blue", 样式
    // condition: ["permissionsData.info"], 校验条件
    // param: "winInfo", 点击时传递的第二个参数
    // handleClick: (this as any).onInfoClick 点击时触发方法，第一个参数为 data
    @Prop({
        default: function () {
            return [];
        }
    })
    readonly btns!: Array<any>;
    // 最终按钮组配置
    get btnList() {
        const me: any = this,
            btns = me.btns;
        return me.isSearch
            ? concat(me.searchBtnConfig, me.clearBtnConfig, btns)
            : btns;
    }

    // 表单配置
    options: any = {
        // 隐藏提交按钮
        submitBtn: false,
        form: {
            inline: true,
            labelWidth: "auto"
        }
    };

    // 点击查询按钮时
    onSearchClick() {
        const me: any = this,
            form = me.getForm();
        // 校验表单
        form.validate((valid: boolean) => {
            if (valid) {
                // 抛出查询事件
                me.search(me.getValues());
            }
        });
    }

    // 获取提交数据
    getValues() {
        const me: any = this,
            form = me.getForm(),
            // 拷贝数据，避免影响组件
            data = cloneDeep(form.formData()),
            // 获取提交数据处理配置
            transform = me.valueTransform;
        // 遍历配置
        forEach(transform, (item: any) => {
            // 字段名称
            const field = item.field,
                // 输出字段组
                fields = item.fields,
                // 字段值
                // 过滤掉空数据
                values: any = compact(data[field]);
            // 如果有值
            if (!isEmpty(values)) {
                if (item.isLast) {
                    const length = values.length - 1;
                    data[fields[length]] = values[length];
                } else {
                    // 遍历输出字段组按顺序赋值
                    forEach(values, (item, i) => {
                        data[fields[i]] = item;
                    });
                }
            }
            // 删除旧数据
            unset(data, field);
        });
        return data;
    }
    // 点击清空按钮时
    onClearClick() {
        const me: any = this,
            form = me.getForm();
        // 重置表单校验状态
        form.clearValidateState();
        // 重置表单值
        form.resetFields();
        if (me.isClearSearch) {
            // 抛出查询事件
            me.search(me.getValues());
        }
    }

    /**
     * 更新表单配置
     *
     * @param {*} [field] searchRules配置中field名称
     * @param {any} [data] 具体配置
     * @param {boolean} [is] 是否覆盖配置
     *
     */
    updateRule(field: any, data: any, is: boolean = false) {
        const form = this.getForm();
        form.updateRule(field, data, is);
    }

    /**
     * 更新表单配置
     *
     * @param {*} [field] searchRules配置中field名称
     * @param {string} [key] 需要更新的字段名称支持name.name
     * @param {any} [data] 具体配置
     * @param {boolean} [is] 是否覆盖配置
     *
     */
    setOptionsByField(field: any, key: any, data: any, is: boolean = false) {
        // 根据字段名称获取默认配置
        let params = {};
        if (is) {
            // 根据字段名称获取默认配置
            params = this.getForm().getRule(field);
        }
        // 设值更新默认配置中的数据
        set(params, key, data);
        this.updateRule(field, params, is);
    }

    /**
     * 设置cascader与select数据
     *
     * @param {*} [field] searchRules配置中field名称
     * @param {any} [data] 具体数据
     * @param {boolean} [isCascader=false] 是否是cascader组件
     */
    setSelectDataByField(field: any, data: any, isCascader: boolean = false) {
        // 为了保证数据是最新的,直接覆盖配置
        this.setOptionsByField(
            field,
            // cascader与select组件需要配置的字段名称不一样
            isCascader ? "props.options" : "options",
            data,
            true
        );
        // 清空当前已选中值
        this.setOptionsByField(field, "value", "");
    }

    // 获取formCreate对象
    getForm() {
        const me: any = this;
        return me.$refs.form.$f;
    }
}
</script>

